package com.luli.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.luli.Utils.HtmlParseUtils;
import com.luli.dao.EsDataDao;
import com.luli.entity.Content;
import com.luli.service.IElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 陆离
 * 2022/5/3 20:21:24
 */
@Service
@Slf4j
public class IElasticSearchServiceImpl implements IElasticSearchService {

    private static final Logger logger = LoggerFactory.getLogger(IElasticSearchServiceImpl.class);

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private EsDataDao esDataDao;

    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    @Override
    public List<Map<String, Object>> selAllData() throws IOException {
        //新建查询索引
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        //构建搜索条件 构造器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //要设定keyword否则将无法查询出结果
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();// 匹配所有
        sourceBuilder.query(matchAllQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(sourceBuilder);
        //获取到es所有数据
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            list.add(documentFields.getSourceAsMap());
        }
        return list;
    }

    @Override
    public Boolean searchKeyword(String keyword) throws IOException {
        //爬取京东数据
        List<Content> contentList = new HtmlParseUtils().parseID(keyword);
        //同步数据库
        esDataDao.AddDataSource(contentList);
        //把查询的数据放到es中
        BulkRequest bulkRequest = new BulkRequest();
        //设置超时
        bulkRequest.timeout(new TimeValue(2000, TimeUnit.SECONDS));
        //前置操作 Elasticsearch创建jd_goods索引
        for (int i = 0; i < contentList.size(); i++) {
            //封装到es数据库
            IndexRequest jd_goods = new IndexRequest("jd_goods").source(JSON.toJSONString(contentList.get(i)), XContentType.JSON);
            //给定es中的id和数据id同步实现删除修改
            jd_goods.id(String.valueOf(contentList.get(i).getId()));
            bulkRequest.add(jd_goods);
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulk.hasFailures();
    }

    @Override
    public List<Map<String, Object>> searchPage(String keyword, int pageNo, int pageSize) throws IOException {
        if (pageNo <= 1) {
            pageNo = 1;
        }
        //条件搜素
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        //新建构造器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //分页
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);

        //精准匹配关键字
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            list.add(documentFields.getSourceAsMap());
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> searchHighlight(String keyword, int pageNo, int pageSize) throws IOException {
        if (pageNo <= 1) {
            pageNo = 1;
        }
        //条件搜素
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        //新建构造器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //分页
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);

        //精准匹配关键字
        //TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        //模糊匹配
        FuzzyQueryBuilder termQueryBuilder = QueryBuilders.fuzzyQuery("title", keyword);
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //构建高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.requireFieldMatch(true);  //多个高亮显示
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);
        //执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            //解析高亮的字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            if (title != null) {
                //拿到高亮字段
                Text[] fragments = title.fragments();
                StringBuilder newTitle = new StringBuilder();
                for (Text fragment : fragments) {
                    newTitle.append(fragment);
                }
                sourceAsMap.put("title", newTitle);
            }
            list.add(sourceAsMap);
        }
        return list;
    }

    @Override
    public RestStatus deleteGood(String id) throws IOException {
        DeleteRequest request = new DeleteRequest("jd_goods", id);
        //同步数据库删除
        esDataDao.deleteDataSource(id);
        request.timeout("1s");
        DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        RestStatus status = delete.status();
        return status;
    }

    @Override
    public Boolean uploadingText(File fileName) {
        logger.info("开始创建模板, 模板文件夹路径:" + "C:\\Users\\lenovo\\Desktop\\json\\");
        boolean res = true;
        try {
            // URL templateUri = ESTools.class.getClassLoader().getResource(templateFilePath);
//            File fileTemplateDir = new File("path");
            File[] templateFiles = fileName.listFiles(new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    return name.endsWith(".json");
                }
            });
            // 遍历文件夹下所有json文件
            for (File file : templateFiles) {
                if (file.exists() && !file.isDirectory()) {
                    try {
                        InputStream is = new FileInputStream(file);
                        String templateJson = IOUtils.toString(is, StandardCharsets.UTF_8);
                        JSONObject templateJsonObject = JSONObject.parseObject(templateJson);
                        String templateName = file.getName().substring(0, file.getName().lastIndexOf("."));
                        logger.info("创建模板, 当前模板名称:" + templateName);
                        PutIndexTemplateRequest request = new PutIndexTemplateRequest(templateName);
                        request.source(templateJson, XContentType.JSON);
                        //优先级
                        request.order(0);
                        //模板匹配的名称方式 test-*
                        request.patterns(Collections.singletonList(templateName + "-*"));
                        request.create(true);// 只创建, 不覆盖
                        AcknowledgedResponse acknowledgedResponse = client.indices().putTemplate(request, RequestOptions.DEFAULT);
                        res = acknowledgedResponse.isAcknowledged();
                        logger.info("创建模板结果:" + res);
                        return res;
                    } catch (Exception e) {
                        logger.error("创建模板错误 ![当前模板名称]" + file.getName() + " [error]" + e.getMessage());
                    }
                } else {
                    logger.warn("文件不存在或文件为文件夹! file path:" + file.toPath());
                }
            }
        } catch (Exception e) {
            logger.error("创建模板错误!error:" + e.getMessage());
        }
        return res;
    }


    @Override
    public Boolean fileUploading(File file) throws IOException {
        //获取文件
//        File file = new File("filePath");//定义一个file对象，用来初始化FileReader
        //校验文件格式
        String fileName = file.getName();
        String substring = fileName.substring(fileName.lastIndexOf("."));
        boolean res = true;
        if (".json".equals(substring) || ".txt".equals(substring)){
            FileReader reader = new FileReader(file);//定义一个fileReader对象，用来初始化BufferedReader
            BufferedReader bReader = new BufferedReader(reader);//new一个BufferedReader对象，将文件内容读取到缓存
            StringBuilder sb = new StringBuilder();//定义一个字符串缓存，将字符串存放缓存中
            try {
                InputStream is = new FileInputStream(file);
                //获取流进行字符编码装换
                String templateJson = IOUtils.toString(is, StandardCharsets.UTF_8);
                //通过fastJson 校验json是否符合规则
                Boolean aBoolean = jsonCheck(templateJson);
                if (aBoolean){
                    String templateName = file.getName().substring(0, file.getName().lastIndexOf("."));
                    logger.info("创建模板, 当前模板名称:" + templateName);
                    PutIndexTemplateRequest request = new PutIndexTemplateRequest(templateName);
                    request.source(templateJson, XContentType.JSON);
                    //优先级
                    request.order(0);
                    //模板匹配的名称方式 test-*
                    request.patterns(Collections.singletonList(templateName + "-*"));
                    request.create(true);// 只创建, 不覆盖
                    AcknowledgedResponse acknowledgedResponse = client.indices().putTemplate(request, RequestOptions.DEFAULT);
                    res = acknowledgedResponse.isAcknowledged();
                    logger.info("创建模板结果:" + res);
                    return res;
                }else {
                    logger.error("JSON解析错误");
                }
            } catch (Exception e) {
                logger.error("创建模板错误 ![当前模板名称]" + file.getName() + " [error]" + e.getMessage());
            }finally {
                bReader.close();
            }
            String str = sb.toString();
            log.info(str);
        }else {
            logger.error("文件类型不符合上传格式=====》》》》" + substring );
        }
        return res;
    }

    private static  Boolean jsonCheck(String jsonStr){
        boolean result = false;
        try {
            Object obj=JSON.parse(jsonStr);
            result = true;
        } catch (Exception e) {
            result=false;
        }
        return result;
    }
}
